When you use the CopyMask or CopyDeepMask procedure (described in the chapter "QuickDraw Drawing"), you can create the source image and its mask in separate offscreen graphics worlds. Plates 3 and 4 at the front of this book illustrate how to use CopyMask in this way. The source image in Plate 3 consists of graduated gray stripes; this image is created in an offscreen graphics world. The mask in Plate 3 consists of a black rectangle alongside a red rectangle; this mask is created in a separate graphics world that shares the same coordinates as the source image.
When the CopyMask procedure copies the grayscale image through this mask, the result is the untitled window illustrated in the bottom half of Plate 3. The black pixels in the mask cause CopyMask to copy directly into the window those pixels from the source image that are masked by the black rectangle. The red pixels in the mask cause CopyMask to alter most of the source pixels masked by the red rectangle when copying them. That is, the source pixels that are completely black are changed to the mask's red when copied into the window. The source pixels that are completely white are left unaltered when copied into the window. The source pixels that are between black and white are given a graduated amount of the mask's red.
Listing 6-2 shows the code that produces the window shown in Plate 3.
Listing 2 Using two offscreen graphics worlds and the CopyMask procedure
PROCEDURE MyCopyBlackAndRedMasks (wp: WindowPtr);
VAR
origPort: GrafPtr;
origDevice: GDHandle;
myErr: QDErr;
myOffScreen1, myOffScreen2: GWorldPtr;
theColor: RGBColor;
i: Integer;
offPixMapHandle1, offPixMapHandle2: PixMapHandle;
good: Boolean;
myRect: Rect;
BEGIN
GetGWorld(origPort, origDevice); {save window's graphics port}
{create an offscreen world for building an image}
myErr := NewGWorld(myOffScreen1, 0, wp^.portRect, NIL, NIL, []);
IF (myOffScreen1 = NIL) OR (myErr <> noErr) THEN
; {handle error here}
{create another offscreen world for building a mask}
myErr := NewGWorld(myOffScreen2, 0, wp^.portRect, NIL, NIL, []);
IF (myOffScreen2 = NIL) OR (myErr <> noErr) THEN
; {handle error here}
SetGWorld(myOffScreen1, NIL); {make first offscreen world the }
{ current port}
offPixMapHandle1 := GetGWorldPixMap(myOffScreen1);
good := LockPixels(offPixMapHandle1); {lock its pixel image}
IF NOT good THEN
; {handle error here}
EraseRect(myOffScreen1^.portRect); {initialize its pixel image}
FOR i := 0 TO 9 DO {draw graduated grayscale stripes for the image}
BEGIN
theColor.red := i * 7168;
theColor.green := i * 7168;
theColor.blue := i * 7168;
RGBForeColor(theColor);
SetRect(myRect, myOffScreen1^.portRect.left, i * 10,
myOffScreen1^.portRect.right, i * 10 + 10);
PaintRect(myRect);
END;
SetGWorld(myOffScreen2, NIL); {make second offscreen world the }
{ current port}
offPixMapHandle2 := GetGWorldPixMap(myOffScreen2);
good := LockPixels(offPixMapHandle2); {lock its pixel image}
IF NOT good THEN
; {handle error here}
EraseRect(myOffScreen2^.portRect); {initialize its pixel image}
SetRect(myRect, 20, 20, 80, 80);
PaintRect(myRect); {paint a black rectangle in the mask}
SetRect(myRect, 100, 20, 160, 80);
theColor.red := $FFFF; theColor.green := $0000; theColor.blue := $0000;
RGBForeColor(theColor);
PaintRect(myRect); {paint a red rectangle in the mask}
SetGWorld(wp, GetMainDevice); {make window the current port}
EraseRect(wp^.portRect); {erase the window before using CopyMask}
CopyMask(GrafPtr(myOffScreen1)^.portBits, {use gray image as source}
GrafPtr(myOffScreen2)^.portBits, {use 2-rectangle image as mask}
GrafPtr(wp)^.portBits, {use window as destination}
myOffScreen1^.portRect,
myOffScreen2^.portRect,
wp^.portRect);
UnlockPixels(offPixMapHandle1); UnlockPixels(offPixMapHandle2);
DisposeGWorld(myOffScreen1); DisposeGWorld(myOffScreen2);
SetGWorld(origPort, origDevice); {restore original graphics port}
END;